/******************************************************************************
* This file is part of is32p218 platform,
* Copyright (c) 2009 HangZhou InfoStrong CO.,LTD. All rights reserved.
* This software may only be used under the terms of a valid, current,
* end user license from InfoStrong.
* Nothing else gives you the right to use this software.   
*
* Name:   drv_utils.c
* Desc:   Utility C file
* Author: Jerry
* Date:   2009-10-14
* Note:   
* History:
*
******************************************************************************/

#include "def.h"
#include "drv_utils.h"
#include "os_api.h"

#define POLY 0x8408
/*
//                                      16   12   5
// this is the CCITT CRC 16 polynomial X  + X  + X  + 1.
// This works out to be 0x1021, but the way the algorithm works
// lets us use 0x8408 (the reverse of the bit pattern).  The high
// bit is always assumed to be set, thus we only use 16 bits to
// represent the 17 bit value.
*/

U16 drv_utils_crc16( const U8 *p_data, U32 len )
{
	U8 i;
	U16 data;
	U16 crc = 0xffff;

	while( len-- )
	{
		for (i=0, data=(U16)0xff & *p_data++;
			i < 8; 
			i++, data >>= 1)
		{
			if ((crc & 0x0001) ^ (data & 0x0001))
				crc = (crc >> 1) ^ POLY;
			else  crc >>= 1;
		}
	}

	crc = ~crc;
	data = crc;
	crc = (crc << 8) | (data >> 8 & 0xff);

	return (crc);
}

/*
* Function Name:
*   drv_utils_cs_calc
* Description:
*   Calculate CheckSum
* Parameters:
*   const U8 *p_data: Data pointer of checksum
*  	U32 cs_len: Length
*  	U8 mode: 0(byte mode); 1(word mode)
* Returns: 
*   U32 Checksum
* Author				Date 
*  Jerry				2009-10-27   
* Note:
*    Accumulate all data, igore C data
*/
U32 drv_utils_cs_calc( const U8 *p_data, U32 cs_len, U8 mode )
{
	U32 checksum = 0;
	if ( 0 == mode )
	{
		while (cs_len--)
		{
			checksum += *p_data++;
		}
	}
	else
	{
		U16 *p_word_data;
		p_word_data = (U16*)p_data;
		while (cs_len>=2)
		{
			checksum += *p_word_data++;
			cs_len -=2;
		}
		if ( cs_len )
		{
			checksum += (*((U8*)p_word_data)|0xFF00);
		}
	}
	return checksum;
}

/*
* Function Name:
*   drv_utils_fifo_push
* Description:
*   FIFO Push one data
* Parameters:
*   FIFO_CTRL_T* p_fifo_obj:
*   U8 in_data:
* Returns:
*   BOOL:
* Author				Date 
*  Jerry				2009-10-14   
* Note:
*    
*/
BOOL drv_utils_fifo_push( FIFO_CTRL_T *p_fifo_obj, U8 in_data )
{
	U32 cpu_sr;
	isOS_ENTER_CRITICAL(cpu_sr);
	if (p_fifo_obj->m_num == p_fifo_obj->m_idx_max )
	{	// FIFO is full
		isOS_EXIT_CRITICAL(cpu_sr);
		return FALSE;
	}
	p_fifo_obj->m_p_buff[p_fifo_obj->m_wr_idx++] = in_data;
	if (p_fifo_obj->m_wr_idx == p_fifo_obj->m_idx_max )
	{	// return to index 0
		p_fifo_obj->m_wr_idx = 0;
	}
	p_fifo_obj->m_num++;
	isOS_EXIT_CRITICAL(cpu_sr);

	return TRUE;
}

/*
* Function Name:
*   drv_utils_fifo_pop
* Description:
*   FIFO pop one data
* Parameters:
*   FIFO_CTRL_T* p_fifo_obj:
*   U8* p_out_data:
* Returns:
*   BOOL:
* Author				Date 
*  Jerry				2009-10-14   
* Note:
*    
*/
BOOL drv_utils_fifo_pop( FIFO_CTRL_T *p_fifo_obj, U8 *p_out_data )
{
	U32 cpu_sr;
	isOS_ENTER_CRITICAL(cpu_sr);
	if ( 0 == p_fifo_obj->m_num )
	{	// FIFO is empty
		isOS_EXIT_CRITICAL(cpu_sr);
		return FALSE;
	}
	*p_out_data = p_fifo_obj->m_p_buff[p_fifo_obj->m_rd_idx++];
	if (p_fifo_obj->m_rd_idx == p_fifo_obj->m_idx_max )
	{	// return to index 0
		p_fifo_obj->m_rd_idx = 0;
	}
	p_fifo_obj->m_num--;

	isOS_EXIT_CRITICAL(cpu_sr);
	return TRUE;
}


/*
* Function Name:
*   drv_utils_fifo_num
* Description:
*   FIFO current number
* Parameters:
*   FIFO_CTRL_T* p_fifo_obj:
* Returns:
*   U16:
* Author				Date 
*  Jerry				2009-10-14   
* Note:
*    
*/
U16 drv_utils_fifo_num( FIFO_CTRL_T *p_fifo_obj )
{
	U16 num;
	U32 cpu_sr;
	isOS_ENTER_CRITICAL(cpu_sr);
	num = p_fifo_obj->m_num;
	isOS_EXIT_CRITICAL(cpu_sr);
	return num;
}
